import tkinter as tk
from tkinter import ttk, scrolledtext, filedialog
import openpyxl
from openai import OpenAI
import threading
from openpyxl.styles import PatternFill, Font, Alignment
from config import mode_config


class TestCaseGeneratorApp:
    def __init__(self, root):
        self.root = root
        # 窗口标题
        self.root.title("AI测试用例生成器")
        # 调用OpenAI
        self.client = OpenAI(
            # 读取配置文件 mode_config
            # api_key="sk-ftcsvzvxnqwcveb-----",
            # base_url="https://api.siliconflow.cn/v1"
            api_key=mode_config.api_key,
            base_url=mode_config.base_url
        )

        # 创建界面组件
        self.create_widgets()
        # 解析后的用例,用于展示在窗口下方预览
        self.res_cse = ""

    # 窗口元素设置
    def create_widgets(self):
        # 输入区域
        input_frame = ttk.LabelFrame(self.root, text="【请在下方输入框内输入需求内容】")  # 标题
        input_frame.pack(padx=10, pady=5, fill="both", expand=True)

        self.txt_input = scrolledtext.ScrolledText(input_frame, height=10)
        self.txt_input.pack(padx=5, pady=5, fill="both", expand=True)

        # 按钮区域
        btn_frame = ttk.Frame(self.root)
        btn_frame.pack(pady=5)
        # 开始生成
        self.btn_generate = ttk.Button(btn_frame, text="一键生成Ai用例", command=self.start_generation)
        self.btn_generate.pack(side=tk.LEFT, padx=5)
        # 导出Excel
        self.btn_export = ttk.Button(btn_frame, text="导出Excel", command=self.export_excel, state=tk.DISABLED)
        self.btn_export.pack(side=tk.LEFT, padx=5)

        # 状态栏
        self.status = ttk.Label(self.root, text="准备就绪", relief=tk.SUNKEN)
        self.status.pack(side=tk.BOTTOM, fill=tk.X)

        # 存储测试用例
        self.test_cases = []

    def start_generation(self):
        self.btn_generate.config(state=tk.DISABLED)
        self.btn_export.config(state=tk.DISABLED)
        self.status.config(text="测试用例，正在生成...，请稍等！")

        # 使用线程避免界面冻结
        threading.Thread(target=self.generate_test_cases).start()

    def generate_test_cases(self):
        try:
            requirement = self.txt_input.get("1.0", tk.END).strip()
            if not requirement:
                raise ValueError("请输入需求内容")

            requirement = requirement.encode('utf-8').decode('utf-8')

            response = self.client.chat.completions.create(
                # 读取配置文件 mode_config
                model=mode_config.model_name,
                # 编写提示词
                messages=[{
                    'role': 'user',
                    'content': f"""
                                1.你是一个高级测试工程师，请根据以下需求生成详细的测试用例；要求按用例分类排序，并包含以下要素：
                                    1. 用例编号
                                    2. 用例描述
                                    3. 优先级（p0/p1/p2）
                                    4. 用例类型
                                    5. 前置条件
                                    6. 操作步骤
                                    7. 预期结果

                                2.需求文档内容：{requirement}
                                        
                                3. 生成的用例，你最少要推测3遍以上
                                
                                4.最后请用以下格式返回：
                                    ### case_001
                                    - 用例描述：[场景+预期结果的内容]
                                    - 优先级：[优先级]
                                    - 用例类型：[分为功能测试、业务、兼容、性能]
                                    - 前置条件：[前置条件]
                                    - 操作步骤：[即详细说明每一步操作步骤，]
                                    - 预期结果：[结果，列出界面显示结果]]
                                    
                                5.限制：只回答软件测试相关内容，其它内容统一回复：“抱歉，超出思考范围！！”
                                """
                }],
                stream=True
            )

            full_response = ""
            for chunk in response:
                content = chunk.choices[0].delta.content or ""
                full_response += content
                print(content)

            self.parse_response(full_response)
            # 结束后，提示信息
            self.status.config(text=f"Ai用例生成完成，请点击【导出Excel】导出查看。 \n【结果预览】：\n{self.res_cse}")
            self.btn_export.config(state=tk.NORMAL)
            print(full_response)
        except Exception as e:
            self.status.config(text=f"错误：{str(e)}")
        finally:
            self.btn_generate.config(state=tk.NORMAL)

    def parse_response(self, response):
        self.test_cases = []
        current_case = {}
        current_field = None
        buffer = []

        for line in response.split('\n'):
            line = line.strip()

            # 检测新测试用例开始
            if line.startswith("###"):
                if current_case:
                    # 保存缓冲区内容到当前字段
                    if current_field and buffer:
                        current_case[current_field] = "\n".join(buffer).strip()
                        buffer = []
                    self.test_cases.append(current_case)

                # 初始化新测试用例
                current_case = {
                    "用例编号": line.split()[-1],
                    "用例描述": "",
                    "优先级": "",
                    "用例类型": "",
                    "前置条件": "",
                    "操作步骤": "",
                    "预期结果": ""
                }
                current_field = None

            # 检测字段开始
            elif line.startswith("-"):
                # 先保存上一个字段的内容
                if current_field and buffer:
                    current_case[current_field] = "\n".join(buffer).strip()
                    buffer = []

                # 确定当前字段
                if "用例描述：" in line:
                    current_field = "用例描述"
                    buffer.append(line.split("：", 1)[1].strip())
                elif "优先级：" in line:
                    current_field = "优先级"
                    buffer.append(line.split("：", 1)[1].strip())
                elif "用例类型：" in line:
                    current_field = "用例类型"
                    buffer.append(line.split("：", 1)[1].strip())
                elif "前置条件：" in line:
                    current_field = "前置条件"
                    buffer.append(line.split("：", 1)[1].strip())
                elif "操作步骤：" in line:
                    current_field = "操作步骤"
                    buffer.append(line.split("：", 1)[1].strip())
                elif "预期结果：" in line:
                    current_field = "预期结果"
                    buffer.append(line.split("：", 1)[1].strip())
                else:
                    current_field = None

            # 如果是字段内容的延续
            elif current_field and line:
                buffer.append(line)

        # 处理最后一个测试用例
        if current_case:
            if current_field and buffer:
                current_case[current_field] = "\n".join(buffer).strip()
            self.test_cases.append(current_case)

        # 调试输出
        print("解析后的测试用例：")
        for case in self.test_cases:
            print(case)
            self.res_cse += str(case)
            self.res_cse += "\n"

    # 导出Excel方法
    def export_excel(self):
        try:
            if not self.test_cases:
                raise ValueError("没有可导出的测试用例")

            # 检查测试用例是否包含必要字段
            for case in self.test_cases:
                if "操作步骤" not in case or "预期结果" not in case:
                    raise ValueError("测试用例缺少必要字段")

            file_path = filedialog.asksaveasfilename(
                defaultextension=".xlsx",
                filetypes=[("Excel文件", "*.xlsx")]
            )

            if not file_path:
                return

            wb = openpyxl.Workbook()
            ws = wb.active
            ws.title = "测试用例"

            # 创建样式对象
            header_fill = PatternFill(
                start_color="D3D3D3",  # 浅灰色
                end_color="D3D3D3",
                fill_type="solid"
            )
            header_font = Font(bold=True)
            wrap_alignment = Alignment(wrap_text=True)  # 自动换行样式

            # 写入表头并应用样式
            headers = ["用例编号", "用例描述", "优先级", "用例类型", "前置条件", "操作步骤", "预期结果"]
            ws.append(headers)

            # 设置标题行样式
            for cell in ws[1]:
                cell.fill = header_fill
                cell.font = header_font
                cell.alignment = Alignment(wrap_text=True, horizontal='center', vertical='center')

            # 写入数据并应用换行样式
            for case in self.test_cases:
                row = [
                    case.get("用例编号", ""),
                    case.get("用例描述", ""),
                    case.get("优先级", ""),
                    case.get("用例类型", ""),
                    case.get("前置条件", ""),
                    case.get("操作步骤", ""),
                    case.get("预期结果", "")
                ]
                ws.append(row)

                # 对新增行应用换行样式
                for cell in ws[ws.max_row]:
                    cell.alignment = wrap_alignment

            # 调整列宽（考虑换行后的内容高度）
            for col in ws.columns:
                max_length = 0
                column = col[0].column_letter
                for cell in col:
                    try:
                        # 计算最长的单行长度（考虑换行）
                        line_lengths = [len(line) for line in str(cell.value).split('\n')]
                        if line_lengths:
                            current_max = max(line_lengths)
                            if current_max > max_length:
                                max_length = current_max
                    except:
                        print("计算最长的单行长度异常")

                adjusted_width = (max_length + 2)
                ws.column_dimensions[column].width = adjusted_width

                # 设置行高（自动调整）
                for row in ws.iter_rows():
                    for cell in row:
                        if cell.value and '\n' in str(cell.value):
                            ws.row_dimensions[cell.row].height = None  # 自动调整行高

            wb.save(file_path)
            self.status.config(text=f"文件已保存至：{file_path}")

        except Exception as e:
            self.status.config(text=f"导出失败：{str(e)}")


if __name__ == "__main__":
    root = tk.Tk()
    app = TestCaseGeneratorApp(root)
    # 设置窗口大小
    root.geometry("600x400")
    root.mainloop()
